package com.miracle9.game.server.message;

import com.miracle9.game.util.GameParameterAssist;
import com.miracle9.game.util.MyApplicationContext;
import com.miracle9.game.util.MyUtil;
import flex.messaging.io.SerializationContext;
import flex.messaging.io.amf.Amf3Input;
import flex.messaging.io.amf.Amf3Output;
import org.apache.log4j.Logger;
import org.apache.mina.core.buffer.IoBuffer;
import org.apache.mina.core.service.IoHandler;
import org.apache.mina.core.session.IdleStatus;
import org.apache.mina.core.session.IoSession;
import org.springframework.stereotype.Service;
import wox.serial.EncodeBase64;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

@Service("fishKingSocketHandler")
public class FishKingSocketHandler implements IoHandler
{
  private Logger logger;
  public static Set<IoSession> x = new HashSet();
  
  public FishKingSocketHandler()
  {
    this.logger = Logger.getLogger(FishKingSocketHandler.class);
  }
  
  public void exceptionCaught(IoSession session, Throwable arg1)
    throws Exception
  {
    session.close(true);
  }
  
  public void messageReceived(IoSession session, Object message)
    throws Exception
  {
    try
    {
      IoBuffer buffer = (IoBuffer)message;
      byte[] contentBytes = new byte[buffer.getInt()];
      buffer.get(contentBytes);
      contentBytes = MyUtil.Base64Decode(contentBytes, (String)GameParameterAssist.bd.get(session));
      Amf3Input ai = new Amf3Input(SerializationContext.getSerializationContext());
      ai.setInputStream(new ByteArrayInputStream(contentBytes));
      Map<String, Object> map = (Map)ai.readObject();
      String url = (String)map.get("method");
      Object[] args = (Object[])map.get("args");
      String[] urls = url.split("/");
      String beanId = urls[0];
      String method = urls[1];
      Object[] args_login = new Object[args.length + 1];
      for (int i = 0; i < args.length; i++) {
        args_login[i] = args[i];
      }
      args_login[(args_login.length - 1)] = session;
      args = args_login;
      Object service = MyApplicationContext.a().getBean(beanId);
      Method m = service.getClass().getDeclaredMethod(method, getClasses(args));
      Object result = m.invoke(service, args);
      if (result != null) {
    	  AmfMessageSend.storageMethodOperating.notifyAllOperating(new StorageMethodEntity(session, method, new Object[] { result }));
      }
    }
    catch (Exception e)
    {
      e.printStackTrace();
    }
  }
  
  private Class<?>[] getClasses(Object[] args)
  {
    try
    {
      Class[] classArray = new Class[args.length];
      for (int i = 0; i < args.length; i++)
      {
        classArray[i] = args[i].getClass();
        if ((args[i] instanceof Integer)) {
          classArray[i] = Integer.TYPE;
        } else if ((args[i] instanceof Boolean)) {
          classArray[i] = Boolean.TYPE;
        } else if ((args[i] instanceof Map)) {
          classArray[i] = Map.class;
        } else if ((args[i] instanceof Long)) {
          classArray[i] = Long.TYPE;
        } else if ((args[i] instanceof Double)) {
          classArray[i] = Double.TYPE;
        } else if ((args[i] instanceof IoSession)) {
          classArray[i] = IoSession.class;
        } else if ((args[i] instanceof Float)) {
          classArray[i] = Float.TYPE;
        }
      }
      return classArray;
    }
    catch (Exception e)
    {
      this.logger.error("", e);
    }
    return null;
  }
  
  public void messageSent(IoSession arg0, Object arg1)
    throws Exception
  {}
  
  public void sessionClosed(IoSession session)
    throws Exception
  {
    GameParameterAssist.bd.remove(session);
    x.remove(session);
    GameParameterAssist.fishKingBi = new ConcurrentHashMap();
    GameParameterAssist.bn_king = new ConcurrentHashMap();
  }
  
  public void sessionCreated(IoSession arg0)
    throws Exception
  {}
  
  public void sessionIdle(IoSession session, IdleStatus arg1)
    throws Exception
  {
    session.close(true);
  }
  
  public static void main(String[] args)
  {
    String key = MyUtil.substringLength(16);
    System.out.println(key);
    
    String indexStr = key.substring(0, 1);
    String lastStr = key.substring(key.length() - 1, key.length());
    key = key.substring(1, key.length() - 1);
    StringBuilder sb = new StringBuilder(key);
    key = String.valueOf(indexStr) + sb.reverse().toString() + lastStr;
    byte[] keys = EncodeBase64.encode(key.getBytes());
    key = new String(keys);
    System.out.println(key);
    
    key = new String(EncodeBase64.decode(key.getBytes()));
    String indexStr1 = key.substring(0, 1);
    String lastStr1 = key.substring(key.length() - 1, key.length());
    StringBuilder sb1 = new StringBuilder(key.substring(1, key.length() - 1));
    System.out.println(String.valueOf(indexStr1) + 
      sb1.reverse().toString() + lastStr1);
  }
  
  public void sessionOpened(IoSession session)
    throws Exception
  {
    try
    {
      this.logger.info("sessionOpened...");
      x.add(session);
      Map<String, Object> arg = new HashMap();
      String key = MyUtil.substringLength(16);
      this.logger.info("key:::" + key);
      GameParameterAssist.bd.put(session, key);
      String indexStr = key.substring(0, 1);
      String lastStr = key.substring(key.length() - 1, key.length());
      key = key.substring(1, key.length() - 1);
      StringBuilder sb = new StringBuilder(key);
      key = String.valueOf(indexStr) + sb.reverse().toString() + lastStr;
      byte[] keys = EncodeBase64.encode(key.getBytes());
      key = new String(keys);
      arg.put("key", key);
      
      HashMap<String, Object> map = new HashMap();
      map.put("method", "manageService/sendServerTime");
      map.put("args", new Object[] { arg });
      ByteArrayOutputStream bout = new ByteArrayOutputStream();
      Amf3Output amf3Output = new Amf3Output(SerializationContext.getSerializationContext());
      amf3Output.setOutputStream(bout);
      amf3Output.writeObject(map);
      amf3Output.flush();
      amf3Output.close();
      byte[] content_out = bout.toByteArray();
      IoBuffer bb = IoBuffer.allocate(content_out.length + 4);
      bb.putInt(content_out.length);
      bb.put(content_out);
      bb.flip();
      session.write(bb);
    }
    catch (Exception e)
    {
      this.logger.error("", e);
    }
  }
}
